package com.bone.common.exception;

import com.bone.common.vo.Result;
import com.bone.common.vo.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.authz.UnauthorizedException;
import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.multipart.MaxUploadSizeExceededException;
import org.springframework.web.servlet.NoHandlerFoundException;

import javax.validation.ConstraintViolationException;

/**
 * @author : WangKeKe
 * @date : 2020/8/13 15:54
 * Description : 用于捕捉全局异常，不包括拦截器异常
 */

@RestControllerAdvice
@Slf4j
public class BoneExceptionHandler {

    /**
     * 处理自定义异常
     **/
    @ExceptionHandler(BoneException.class)
    public Result<String> handleMyException(BoneException e) {
        log.error(e.getMessage(), e);
        return Result.error(e.getMessage());
    }

    /**
     * 处理路径错误异常
     **/
    @ExceptionHandler(NoHandlerFoundException.class)
    public Result<String> handlerNoFoundException(NoHandlerFoundException e) {
        log.error(e.getMessage(), e);
        return Result.error("路径不存在，请检查路径是否正确");
    }

    /**
     * 数据库插入数据异常
     **/
    @ExceptionHandler(DuplicateKeyException.class)
    public Result<String> handleDuplicateKeyException(DuplicateKeyException e) {
        log.error(e.getMessage(), e);
        return Result.error("数据库中已存在该记录");
    }

    /**
     * 数据库字超出限制异常
     **/
    @ExceptionHandler(DataIntegrityViolationException.class)
    public Result<String> handleDataIntegrityViolationException(DataIntegrityViolationException e) {
        log.error(e.getMessage(), e);
        return Result.error("字段太长,超出数据库字段的长度");
    }

    /**
     * 无权限异常
     **/
    @ExceptionHandler({UnauthorizedException.class, AuthorizationException.class})
    public Result<?> handleAuthorizationException(AuthorizationException e) {
        log.error(e.getMessage(), e);
        return Result.noAuth("没有权限，请联系管理员授权");
    }

    /**
     * spring默认上传大小100MB 超出大小捕获异常
     **/
    @ExceptionHandler(MaxUploadSizeExceededException.class)
    public Result<String> handleMaxUploadSizeExceededException(MaxUploadSizeExceededException e) {
        log.error(e.getMessage(), e);
        return Result.error("文件大小超出10MB限制, 请压缩或降低文件质量! ");
    }

    /**
     * 请求方法不支持异常
     **/
    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
    public Result<String> httpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
        StringBuilder buffer = new StringBuilder();
        buffer.append("不支持");
        buffer.append(e.getMethod());
        buffer.append("请求方法，");
        buffer.append("支持以下");
        String[] methods = e.getSupportedMethods();
        if (methods != null) {
            for (String str : methods) {
                buffer.append(str);
                buffer.append("、");
            }
        }
        log.error(buffer.toString(), e);
        return Result.error(ResultCode.METHOD_NOT_SUPPORT.getCode(), buffer.toString());
    }


    @ExceptionHandler({MethodArgumentNotValidException.class})
    public Result<String> handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        String msg = handleMsg(e.getBindingResult());
        log.error(msg);
        return Result.error(ResultCode.VALIDATE_FAILED.getCode(), msg);
    }

    @ExceptionHandler({BindException.class})
    public Result<String> handleBindException(BindException e) {
        String msg = handleMsg(e.getBindingResult());
        log.error(msg);
        return Result.error(ResultCode.VALIDATE_FAILED.getCode(), msg);
    }

    @ExceptionHandler(ConstraintViolationException.class)
    public Result<String> handleConstraintViolationException(ConstraintViolationException e) {
        log.error(e.getMessage(), e);
        return Result.error(ResultCode.VALIDATE_FAILED.getCode(), e.getMessage().substring(e.getMessage().indexOf(":") + 1));
    }

    private String handleMsg(BindingResult bindingResult) {
        StringBuilder sb = new StringBuilder("校验失败:");
        for (FieldError fieldError : bindingResult.getFieldErrors()) {
            sb.append(fieldError.getDefaultMessage()).append(",");
        }
        return sb.substring(0, sb.length() - 1);
    }


    /**
     * 其他异常
     **/
    @ExceptionHandler(Exception.class)
    public Result<String> handleException(Exception e) {
        log.error(e.getMessage(), e);
        return Result.error("操作失败，" + e.getMessage());
    }

}
